iT邦幫忙

2023 iThome 鐵人賽

DAY 22
0
SideProject30

初探 Godot系列 第 22

[DAY 22] 組合角色

  • 分享至 

  • xImage
  •  

今日目標:重建背景並組合角色


▍事前準備

昨天我們將障礙加入到背景場景中,並能隨機在範圍中生成。

不幸的是今天將角色加入時,發現碰撞似乎會無法正常運作,所以先重新調整我們的背景場景做一些小改動,做錯誤中學習也是一個難得的經驗QQ。


▍出發

  • 建立一個新場景作為我們替代的背景並儲存到 Scenes 中。

  • 在場景中建立一個 Node2D 節點作為根節點命名為 Background,接著在這個根節點下建立兩個 Sprite2D 節點作為我們循環的背景圖節點並重新命名及在屬性面板中設定 Texture 圖片。

    # 結構如下:
    |--Background (Node2D)
    |   |--DynamicBG2 (Sprite2D)
    |   |--DynamicBG1 (Sprite2D)
    
  • 接著我們複製之前的背景程式做一些修改後使用

    1. 將背景物件的型別更改為 Sprite2D 並更新初始化的物件及調整第二背景移動方法。
    var background1:Sprite2D
    var background2:Sprite2D
    
    func _ready():
        # ...
        background1 = $DynamicBG1
        background2 = $DynamicBG2
        # ...
    
        # 改成使用 set_position
        background2.set_position(Vector2(0, -viewpoint_height))
    
    1. 調整滾動背景方法:scroll_background
    # 更新輸入參數型別
    func scroll_background(bg:Sprite2D):
        # 更新獲取位置方法
        var offset = bg.position
    
        offset.y += speed * get_process_delta_time()
    
        if offset.y >= viewpoint_height:
            bg.set_texture(randomBackground[randi()%randomBackground.size()])
            offset.y = offset.y - viewpoint_height*2
    
            # set new randf pos for obstacles
            for obstacle in backgrounds_to_obstacles[bg]:
                obstacle.position = get_randf_pos()
    
        # 更新設置位置方法
        bg.set_position(offset)
    
    1. 將屬性面板的曝露出來的背景圖片陣列以及障礙物陣列放回即完成。
      https://ithelp.ithome.com.tw/upload/images/20231007/20162875aG4vBcEndC.png
    2. 最後我們到 2D 頁面將根節點移到顯示畫面中,可以在右邊屬性面板的 Transform 更改 position
      https://ithelp.ithome.com.tw/upload/images/20231007/201628753uTDfZjNPT.png
  • 新增暴露角色起始位置方法,更改角色腳本

    @export var start_position :Vector2 = Vector2(360, 1300)
    
    func _ready():
        # ...
        player.position = start_position
        # ...
    
  • 建立遊戲的主要場景

    1. 新建場景並儲存到 Scenes 下。
    2. 建立根節點 Node
    3. 點擊左邊場景頁面的 Instantiate child scene 將我們的背景場景和角色場景放到根節點下
    # 結構如下:
    |-- Main (Node)
    |   |--Background (Scene)
    |   |--Player (Scene)
    

▍執行

Yes

▍完成

完整檔案

  1. 新的背景程式
extends Node2D

@export var randomBackground:Array
@export var speed: float = 500

# obstacles
@export var obstacles:Array

var backgrounds_to_obstacles:Dictionary

var background1:Sprite2D
var background2:Sprite2D

var viewpoint_width:float
var viewpoint_height:float
# Called when the node enters the scene tree for the first time.
func _ready():
	viewpoint_width = get_viewport().size.x
	viewpoint_height = get_viewport().size.y
	
	background1 = $DynamicBG1
	background2 = $DynamicBG2
	
	backgrounds_to_obstacles = {
		background1: [],
		background2: []
	}
	
	# create reused obstacles
	for bg in backgrounds_to_obstacles.keys():
		for obstacle in obstacles:
			var obstacle_instantiate = obstacle.instantiate()
			obstacle_instantiate.position = Vector2(0, -viewpoint_height*2)
			bg.add_child(obstacle_instantiate)
			backgrounds_to_obstacles[bg].append(obstacle_instantiate)

	background2.set_position(Vector2(0, -viewpoint_height))

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
	scroll_background(background1)
	scroll_background(background2)
	
func scroll_background(bg:Sprite2D):
	var offset = bg.position
	
	offset.y += speed * get_process_delta_time()
	
	if offset.y >= viewpoint_height:
		bg.set_texture(randomBackground[randi()%randomBackground.size()])
		offset.y = offset.y - viewpoint_height*2
		
		# set new randf pos for obstacles
		for obstacle in backgrounds_to_obstacles[bg]:
			obstacle.position = get_randf_pos()
		
	bg.set_position(offset)
		
func get_randf_pos():
	return Vector2(randf_range(-viewpoint_width/2, viewpoint_width/2), randf_range(-viewpoint_height/2, viewpoint_height/2))
  1. 角色微調 (僅有 process 前的程式碼,非完整)
extends CharacterBody2D

# shader
var anime_sprite = AnimatedSprite2D

# CharacterBody2D
var direction:Vector2
var dragged:bool = false
var oriPos: Vector2
var player: CharacterBody2D
var player_anime: AnimatedSprite2D

# MovementUI
var movement_ui: Node2D

# Collision Handling
@export var slow_speed:float = 1
@export var base_speed:float = 5

# start position
@export var start_position :Vector2 = Vector2(360, 1300)

var speed:float = base_speed

var invincible_timer:Timer
var slow_timer:Timer
var stop_timer:Timer
const DEFAULT = "DEFAULT"
var state:String = DEFAULT

# Called when the node enters the scene tree for the first time.
func _ready():
	
	anime_sprite = $AnimatedSprite2D
		
	movement_ui = $"../MovementUI"
	movement_ui.visible = false
	
	player = $"."
	player_anime = player.get_node("AnimatedSprite2D")
	
	# init player postition
	player.position = start_position
	
	invincible_timer = $"../InvincibleTimer"
	invincible_timer.timeout.connect(_on_invincible_timeout)
	slow_timer = $"../SlowTimer"
	slow_timer.timeout.connect(_on_slow_timeout)
	stop_timer = $"../StopTimer"
	stop_timer.timeout.connect(_on_stop_timeout)

# ...
# 其他方法未更動略過

:)


上一篇
[DAY 21] 組合背景及障礙物 (Dictionary)
下一篇
[DAY 23] 組合移動障礙 (VisibleOnScreenNotifier2D)
系列文
初探 Godot30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言